﻿using Autofac;
using DJY.Code;
using DJY.Domain.Entity.SystemManage;
using DJY.Domain.ViewModel;
using DJY.Service.SystemSecurity;
using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Data.Entity;
using System.Data.SqlClient;
using System.Linq;

namespace DJY.Application.SystemSecurity
{
    public class SysService : ISysService
    {

        //系统角色
        const string SYS_ROLE_ITEM = "SYS_ROLES";
        //系统岗位
        const string SYS_DUTY_ITEM = "SYS_DUTIES";

        /// <summary>
        /// 获取流水序列号
        /// </summary>
        /// <param name="key">值</param>
        /// <param name="timeFlag">时间格式</param>
        /// <param name="start">起始值，比如10000</param>
        /// <param name="length">序号长度，默认6，不足左侧补0</param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException">timeFlag不能为空</exception>
        public string GetNextSerialNo(string key, string timeFlag,
            int start = 0, int length = 6)
        {
            if (string.IsNullOrEmpty(timeFlag))
            {
                throw new ArgumentNullException("timeFlag不能为空");
            }

            if (key == null)
            {
                key = string.Empty;
            }

            using (var scope = OperatorProvider.BeginLifetimeScope(null))
            {
                using (var db = scope.Resolve<DbContext>())
                {
                    DbParameter[] paras = new DbParameter[4];
                    paras[0] = new SqlParameter("@key", System.Data.SqlDbType.VarChar, 20);
                    paras[0].Value = key;

                    paras[1] = new SqlParameter("@timeFlag", System.Data.SqlDbType.VarChar, 20);
                    paras[1].Value = timeFlag;

                    paras[2] = new SqlParameter("@start", System.Data.SqlDbType.Int);
                    paras[2].Value = start;

                    paras[3] = new SqlParameter("@len", System.Data.SqlDbType.Int);
                    paras[3].Value = length;

                    return db.Database.SqlQuery<string>("EXEC pro_getNextValue @key,@timeFlag,@start,@len", paras).FirstOrDefault();
                }
            }
        }

        /// <summary>
        /// 获取用户指定模块按钮组
        /// </summary>
        /// <param name="userId">登陆用户</param>
        /// <param name="moduleCode">模块编码</param>
        /// <returns></returns>
        public List<string> GetUserModuleButtons(string userId, string moduleCode)
        {
            return GetUserModuleBtns(userId, moduleCode);
        }

        /// <summary>
        /// 获取系统模块
        /// </summary>
        /// <param name="orgId">单位ID</param>
        /// <returns></returns>
        public List<SysModuleEntity> GetSysModules(string orgId)
        {
            List<SysModuleEntity> list = OperatorProvider.GetCache<List<SysModuleEntity>>(CacheKeys.Sys_Module);
            if(list == null)
            {
                using (var scope = OperatorProvider.BeginLifetimeScope(null))
                {
                    using (var db = scope.Resolve<DbContext>())
                    {
                        list = GetSysModules(db, orgId);

                        if(list.Count > 0)
                        {
                            OperatorProvider.SetCache(CacheKeys.Sys_Module, list);
                        }
                    }
                }
            }

            return list;
        }

        /// <summary>
        /// 获取系统模块
        /// </summary>
        /// <param name="db">数据库实例</param>
        /// <param name="orgId">单位ID</param>
        /// <returns></returns>
        public List<SysModuleEntity> GetSysModules(DbContext db,string orgId)
        {
            if(db == null)
            {
                return GetSysModules(orgId);
            }

            List<SysModuleEntity> list = OperatorProvider.GetCache<List<SysModuleEntity>>(CacheKeys.Sys_Module);
            if (list == null)
            {
                list = db.Set<SysModuleEntity>().Where(m => m.F_OrganizeId == orgId && m.F_EnabledMark).ToList();

                if (list.Count > 0)
                {
                    OperatorProvider.SetCache(CacheKeys.Sys_Module, list);
                }
            }
            return list;
        }

        /// <summary>
        /// 获取用户指定模块按钮组
        /// </summary>
        /// <param name="userId">登陆用户</param>
        /// <param name="moduleCode">模块编码</param>
        /// <returns></returns>
        public static List<string> GetUserModuleBtns(string userId, string moduleCode)
        {
            if (string.IsNullOrEmpty(userId) || string.IsNullOrEmpty(moduleCode))
            {
                return new List<string>();
            }
            using (var scope = OperatorProvider.BeginLifetimeScope(null))
            {
                using (var db = scope.Resolve<DbContext>())
                {
                    return db.Set<SysUserEntity>().Where(u => u.F_Id == userId)
                         .Join(db.Set<SysRoleAuthorizeEntity>().Where(r => r.F_ObjectType == 1 && r.F_ItemType == 2),
                         u => u.F_RoleId, r => r.F_ObjectId, (u, r) => new { r.F_ItemId })
                         .Join(db.Set<SysModuleEntity>().Where(m => m.F_EnCode == moduleCode && m.F_EnabledMark)
                         .Join(db.Set<SysModuleButtonEntity>().Where(b => b.F_EnabledMark),
                         m => m.F_Id, b => b.F_ModuleId, (m, b) => new { b.F_Id, b.F_EnCode }),
                         ra => ra.F_ItemId, mb => mb.F_Id, (ra, mb) => mb.F_EnCode).ToList();
                }
            }
        }

        /// <summary>
        /// 获取用户岗位
        /// </summary>
        /// <param name="userId">登陆用户</param>
        /// <returns></returns>
        public Tuple<string, string, string> GetUserDuty(string userId)
        {
            using (var scope = OperatorProvider.BeginLifetimeScope(null))
            {
                using (var db = scope.Resolve<DbContext>())
                {
                    return GetUserDuty(db, userId);
                }
            }
        }

        /// <summary>
        /// 获取用户岗位
        /// </summary>
        /// <param name="db">数据库查询</param>
        /// <param name="userId">登陆用户</param>
        /// <returns></returns>
        public static Tuple<string, string, string> GetUserDuty(DbContext db, string userId)
        {
            var duty = db.Set<SysUserEntity>().Where(u => u.F_Id == userId)
                .Join(db.Set<SysRoleEntity>().Where(o=>o.F_CategoryId == 2), u => u.F_DutyId,
                d => d.F_Id, (u, d) => new
                {
                    Duty = d.F_FullName,
                    DutyId = d.F_Id,
                    Code = d.F_EnCode
                }).FirstOrDefault();

            return duty == null ? null : Tuple.Create(duty.DutyId, duty.Code, duty.Duty);
        }

        /// <summary>
        /// 获取系统字典
        /// </summary>
        /// <param name="codes"></param>
        /// <returns></returns>
        public List<SysItem> GetSysItems(List<string> codes)
        {
            if (codes == null || codes.Count == 0)
                throw new ArgumentNullException();

            OperatorModel user = OperatorProvider.GetCurrent();
            if (user == null)
            {
                return new List<SysItem>();
            }

            using (var scope = OperatorProvider.BeginLifetimeScope(null))
            {
                using (var db = scope.Resolve<DbContext>())
                {
                    List<SysItem> result = new List<SysItem>();

                    if (codes.Any(c => c.Equals(SYS_ROLE_ITEM, StringComparison.OrdinalIgnoreCase)))
                    {
                        SysItem roleItem = new SysItem()
                        {
                            code = SYS_ROLE_ITEM
                        };
                        result.Add(roleItem);
                        roleItem.codes = db.Set<SysRoleEntity>().Where(r=> r.F_CategoryId == 1 && r.F_EnabledMark 
                            && r.F_OrganizeId == user.CompanyId)
                            .OrderBy(r => r.F_SortCode).ToList()
                            .Select(r => new SysItemCode()
                            {
                                id = r.F_Id,
                                code = r.F_EnCode,
                                desc = r.F_Description,
                                text = r.F_FullName
                            }).ToList();

                        codes.Remove(SYS_ROLE_ITEM);
                    }

                    if (codes.Any(c => c.Equals(SYS_DUTY_ITEM, StringComparison.OrdinalIgnoreCase)))
                    {
                        SysItem dutyItem = new SysItem()
                        {
                            code = SYS_DUTY_ITEM
                        };
                        result.Add(dutyItem);
                        dutyItem.codes = db.Set<SysRoleEntity>().Where(r => r.F_CategoryId == 2 && r.F_EnabledMark
                            && r.F_OrganizeId == user.CompanyId)
                            .OrderBy(r => r.F_SortCode).ToList()
                            .Select(r => new SysItemCode()
                            {
                                id = r.F_Id,
                                code = r.F_EnCode,
                                desc = r.F_Description,
                                text = r.F_FullName
                            }).ToList();

                        codes.Remove(SYS_DUTY_ITEM);
                    }

                    if (codes.Count == 0)
                    {
                        return result;
                    }

                    result = db.Set<SysItemsEntity>().Where(i => codes.Contains(i.F_EnCode)
                    && i.F_EnabledMark).Select(i => new SysItem
                    {
                        id = i.F_Id,
                        code = i.F_EnCode,
                        text = i.F_FullName,
                        desc = i.F_Description
                    }).ToList();

                    codes = result.Select(i => i.id).ToList();

                    var itemDetails = db.Set<SysItemsDetailEntity>().Where(d => codes.Contains(d.F_ItemId)
                    && d.F_EnabledMark)
                    .OrderBy(d => d.F_SortCode).Select(d => new SysItemCode
                    {
                        id = d.F_Id,
                        parent = d.F_ItemId,
                        code = d.F_ItemCode,
                        text = d.F_ItemName,
                        desc = d.F_Description,
                        isDefault = d.F_IsDefault
                    }).ToList();

                    result.ForEach(i =>
                    {
                        i.codes = itemDetails.Where(d => d.parent == i.id).ToList();
                    });

                    return result;
                }
            }
        }

        /// <summary>
        /// 获取系统字典
        /// </summary>
        /// <param name="cateCode">分类编码</param>
        /// <param name="code">字典编码</param>
        /// <returns></returns>
        public SysItemCode GetSysItemCode(string cateCode, string code)
        {
            if (string.IsNullOrEmpty(cateCode) || string.IsNullOrEmpty(code))
                throw new ArgumentNullException();

            using (var scope = OperatorProvider.BeginLifetimeScope(null))
            {
                using (var db = scope.Resolve<DbContext>())
                {

                    return db.Set<SysItemsEntity>().Where(i => i.F_EnCode == cateCode).Join(db.Set<SysItemsDetailEntity>()
                        .Where(d => d.F_ItemCode == code && d.F_EnabledMark),
                        i => i.F_Id, d => d.F_ItemId, (i, d) => new SysItemCode
                        {
                            id = d.F_Id,
                            parent = d.F_ItemId,
                            code = d.F_ItemCode,
                            text = d.F_ItemName,
                            desc = d.F_Description,
                            isDefault = d.F_IsDefault
                        }).FirstOrDefault();
                }
            }
        }

        /// <summary>
        /// 检查用户是否有功能权限
        /// </summary>
        /// <param name="userId">用户</param>
        /// <param name="menuCode">菜单</param>
        /// <param name="funcs">功能</param>
        /// <returns></returns>
        internal static List<string> CheckRight(DbContext db, string userId, string menuCode, List<string> funcs)
        {
            return db.Set<SysUserEntity>().Where(u => u.F_Id == userId)
                .Join(db.Set<SysRoleAuthorizeEntity>().Where(r => r.F_ObjectType == 1 && r.F_ItemType == 2),
                u => u.F_RoleId, r => r.F_ObjectId, (u, r) => new { r.F_ItemId, r.F_Id })
                .Join(db.Set<SysModuleEntity>().Where(m => m.F_EnCode == menuCode)
                .Join(db.Set<SysModuleButtonEntity>().Where(b => funcs.Contains(b.F_EnCode)),
                m => m.F_Id, b => b.F_ModuleId, (m, b) => new { b.F_Id, b.F_EnCode }),
                ra => ra.F_ItemId, mb => mb.F_Id, (ra, mb) => mb.F_EnCode).ToList();
        }
    }
}
